<?php

	/**
	 * Verifies bootstrapper execution to ensure file
	 * necessities, and disabling direct access
	 */
	defined('ENGINE') or exit;
	
	/**
	 * Datastore cache, this enables datastore caching for
	 * databases.  This assumes the datastore table and 
	 * everything else required for the database based
	 * datastore is setup
	 */
	final class Datastore
	{
		/**
		 * Private instance to the Engine registry
		 */
		protected $engine;
		
		/**
		 * Holds the cached elements from the datastore
		 */
		protected $cache		= array();
		
		/**
		 * Boolean of if the datastore is ready for use
		 */
		protected $ready		= false;
		
		/**
		 * Constructor
		 */
		public function __construct()
		{
			$this->engine = Engine::init();
			
			if($this->engine->db === false)
			{
				throw new Engine_Basic_Exception('A database driver must be initialized before the datastore can be constructed');
			}
			
			$this->ready = true;
		}
		
		/**
		 * Quick reference for overloading of a loaded
		 * element in the datastore
		 */
		public function __get($name)
		{
			if(isset($this->cache[$name]))
			{
				return($this->cache[$name]);
			}
			else if($this->cache(array($name)))
			{
				return($this->cache[$name]);
			}
			
			return(false);
		}
		
		/**
		 * Fetches a new item from the datastore cache
		 */
		public function fetch($name)
		{
			return($this->name{$name});
		}
		
		/**
		 * Frees a datastore from the loaded cache
		 */
		public function free($name)
		{
			if(isset($this->cache[$name]))
			{
				unset($this->cache[$name]);
			}
		}
		
		/**
		 * Rebuilds a datastore element if it already exists, or adds
		 * a new entry in the datastore if no elements with that name
		 * already exists.  To delete a datastore element completely
		 * the data parameter must be set to NULL.  If the delay 
		 * parameter is set to true, then the current cache data will
		 * not be updated with the new data.
		 */
		public function rebuild($name, array $data = NULL, $delay = true)
		{
			if(!$this->ready)
			{
				return(false);
			}
			else if(is_null($data))
			{
				$sql = sprintf('DELETE FROM `' . PREFIX . 'datastore` WHERE `name` = \'%s\' LIMIT 1;', $this->engine->db->escape($name));
			}
			else
			{
				$sql = sprintf('REPLACE INTO `' . PREFIX . 'datastore` (`name`, `data`) VALUES (\'%s\', \'%s\')', $this->engine->db->escape($name), $this->engine->db->escape($data));
			}
			
			if($delay)
			{
				return($this->engine->db->set_shutdown_query($sql));
			}
			
			$return = $this->engine->db->query($sql);
			
			if($return)
			{
				if(is_null($data))
				{
					unset($this->cache[$name]);
				}
				else
				{
					$this->cache[$name] = $data;
				}
			}
			
			return($return);
		}
		
		/**
		 * Caches a set of elements from the datastore into
		 * the current cache
		 */
		public function cache(array $elements, array &$error_buffer = NULL)
		{
			if(!$this->ready || !sizeof($elements))
			{
				return(false);
			}
			
			$result = $this->engine->db->query('SELECT `name`, `data` FROM `' . PREFIX . 'datastore` WHERE `name` IN (\'%s\');', join('\', \'', array_map(array($this->engine->db, 'escape'), $elements)));
			
			if($result === false)
			{
				if(!is_null($error_buffer))
				{
					$error_buffer = $elements;
				}
				
				return(false);
			}
			
			$loaded = array();
			
			while($row = $result->fetch_object())
			{
				$row->data = @unserialize($row->data);
				
				if($row->data !== false)
				{
					$loaded[]					= $row->name;
					$this->cache[$row->name]	= $row->data;
				}
			}
			
			if(!is_null($error_buffer))
			{				
				$diff = array_diff($elements, $loaded);
				
				if(sizeof($diff))
				{
					$error_buffer = $diff;
				}
				
				return(false);
			}
			
			return(true);
		}
	}

?>